package com.example.demo.phone.util;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.TrustStrategy;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.Optional;



public class HttpUtil {


    public static String getForString(String url, Map<String, Object> uriParams) {
        String paramsUrl = buildParamsUrl(url, uriParams);
        HttpGet get = new HttpGet(paramsUrl);
        return doExecute(get, getStringResponseHandler());
    }

    private static String buildParamsUrl(String url, Map<String, Object> uriParams) {
        return UrlUtil.createUrl(url, uriParams);
    }

    public static <T> T getForEntity(String url, Map<String, Object> uriParams, Class<T> clazz) {
        String json = getForString(url, uriParams);
        return StringUtils.isBlank(json) ? null : JSON.parseObject(json, clazz);
    }

    private static <T> T doExecute(HttpUriRequest request, ResponseHandler<T> handler) {
        T result = null;
        try {
            result = getClient().execute(request, handler);
        } catch (IOException e) {
            System.out.printf("execute request failed {}");
        }
        return result;
    }

    private static HttpClient getClient() {
        return createSSLInsecureClient();
    }

    private static ResponseHandler<String> getStringResponseHandler() {
        return (httpResponse) -> {
            HttpEntity entity = httpResponse.getEntity();
            return EntityUtils.toString(entity, Charset.defaultCharset());
        };
    }

    public static String postJson(String url, Map<String, Object> uriParams, Object object) {
        String paramsUrl = buildParamsUrl(url, uriParams);
        HttpPost post = new HttpPost(paramsUrl);

        post.addHeader("Content-Type", "application/json");

        if (null != object) {
            //json serialize
            String body = JSON.toJSONString(object);
            StringEntity entity = new StringEntity(body, Charset.defaultCharset());
            post.setEntity(entity);
        }

        return doExecute(post, getStringResponseHandler());
    }

    public static String postJson(String url, Map<String, Object> uriParams, Map<String, Object> headers, Object object) {
        String paramsUrl = buildParamsUrl(url, uriParams);
        HttpPost post = new HttpPost(paramsUrl);

        post.addHeader("Content-Type", "application/json");

        Optional.ofNullable(headers).ifPresent(
                t -> t.entrySet().stream().forEach(entry -> post.addHeader(entry.getKey(), entry.getValue().toString()))
        );

        if (null != object) {
            //json serialize
            String body = JSON.toJSONString(object);
            StringEntity entity = new StringEntity(body, Charset.defaultCharset());
            post.setEntity(entity);
        }

        return doExecute(post, getStringResponseHandler());
    }

    public static String getJson(String url, Map<String, Object> uriParams, Map<String, Object> headers) {
        String paramsUrl = buildParamsUrl(url, uriParams);
        HttpGet get = new HttpGet(paramsUrl);
        get.addHeader("Content-Type", "application/json");
        Optional.ofNullable(headers).ifPresent(
                t -> t.entrySet().stream().forEach(entry -> get.addHeader(entry.getKey(), entry.getValue().toString()))
        );
        return doExecute(get, getStringResponseHandler());
    }

    /**
     * 创建一个SSL信任所有证书的httpClient对象
     *
     * @return
     */
    public static CloseableHttpClient createSSLInsecureClient() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                // 默认信任所有证书
                @Override
                public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
                    return true;
                }
            }).build();
            // AllowAllHostnameVerifier: 这种方式不对主机名进行验证，验证功能被关闭，是个空操作(域名验证)
            SSLConnectionSocketFactory sslcsf = new SSLConnectionSocketFactory(sslContext,
                    SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            return HttpClients.custom().setDefaultRequestConfig(RequestConfig.custom().setConnectTimeout(20000).setConnectionRequestTimeout(20000)
                    .setSocketTimeout(20000).build())
                    .setSSLSocketFactory(sslcsf).build();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return HttpClients.createDefault();
    }

    public static boolean tryAccess(String url) {
        String result = getForString(url, null);
        return StringUtils.isNotBlank(result);
    }

}
